﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices; // For using DllImport
using Interop = Microsoft.Office.Interop;
using Net.Sgoliver;

namespace DienLib.OfficeLib
{
    public class Outlook
    {
        const string Ratio_MailExcel = "1:3";
        static wOutlook myOutlook;
        static wExcel myExcel;

        public static void sendReport(string title, string to, string cc, string attachment, System.Windows.Documents.FlowDocument body, System.Windows.Documents.FlowDocument signature)
        {
            System.Media.SystemSounds.Beep.Play();
            #region Check Attachment Exist
            //attachment = "D:/Perf Initial.xlsx";
            if (attachment.LastIndexOf('\\') > 1 && attachment.Length > attachment.LastIndexOf('\\') + 1)
            {  // Thoa man cac yeu cau co ban cua mot duong dan file
                if (!System.IO.File.Exists(attachment))
                { // Duong dan file khong ton tai
                    string folder = attachment.Substring(0, attachment.LastIndexOf('\\'));
                    if (!System.IO.Directory.Exists(folder)) folder = "::" + MyComputer; // Khong ton tai thi Mac Dinh Computer
                    attachment = getFilePath("ATTACH FILE FOR YOUR REPORT : \"" + title + "\"",
                        attachment.Substring(attachment.LastIndexOf('\\') + 1), folder);
                }
            }
            else attachment = getFilePath("ATTACH FILE FOR YOUR REPORT : \"" + title + "\"",
                "Please attach your file", "::" + MyComputer); // Khong phai la mot duong dan file
            #endregion

            if (attachment.Length > 0)
            {
                myOutlook = new wOutlook(title, to, cc, body, signature, attachment);
                myExcel = new wExcel(attachment, new Interop.Excel.WorkbookEvents_AfterSaveEventHandler(delegate(bool Success) { if (Success) myOutlook.ReAttach(); }));
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("You did not attached any file yet, Please ATTACH FILE YOURSELF before send !",
                "Auto Sending \"" + title + "\"", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
                myOutlook = new wOutlook(title, to, cc, body, signature);
                myExcel = new wExcel();
            }

            char l = Ratio_MailExcel[0];
            byte rt_Mail = (byte)(Ratio_MailExcel[0] - '0');
            byte rt_Excel = (byte)(Ratio_MailExcel[2] - '0');

            // 2 Ways to use MoveWindow or myExcel.Top/Left & Width/Height
            myExcel.SetWorkArea(new System.Drawing.Rectangle(System.Windows.Forms.SystemInformation.WorkingArea.Width * rt_Mail / (rt_Mail + rt_Excel),
                System.Windows.Forms.SystemInformation.WorkingArea.Y, System.Windows.Forms.SystemInformation.WorkingArea.Width * rt_Excel / (rt_Mail + rt_Excel),
                System.Windows.Forms.SystemInformation.WorkingArea.Height));

            try
            {
                myOutlook.SetWorkArea(new System.Drawing.Rectangle(System.Windows.Forms.SystemInformation.WorkingArea.X, System.Windows.Forms.SystemInformation.WorkingArea.Y,
                System.Windows.Forms.SystemInformation.WorkingArea.Width * rt_Mail / (rt_Mail + rt_Excel), System.Windows.Forms.SystemInformation.WorkingArea.Height));
            }
            catch (System.Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }


        }

        const string MyComputer = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
        private static string getFilePath(string title, string initFile, string initFolder)
        {
            System.Windows.Forms.OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog(); // Ton tai thi nhu ben tren da chon thu muc trich tu attachment
            dialog.InitialDirectory = initFolder;
            dialog.FileName = initFile;
            dialog.Title = title;
            dialog.ShowDialog();
            if (System.IO.File.Exists(dialog.FileName)) return dialog.FileName; else return "";
        }
    }

    class wExcel : IDisposable
    {
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

        private Interop.Excel.Application _app = null;
        private Interop.Excel.Workbook _workbook = null;
        private string _filename = null;
        private System.Timers.Timer _disposeTimer = null;

        public wExcel(string filename = null, Interop.Excel.WorkbookEvents_AfterSaveEventHandler AfterSaveDo = null)
        {
            _app = new Interop.Excel.Application();
            
            if (filename != null)
            {
                _filename = filename;
                _workbook = _app.Workbooks.Open(filename, Type.Missing, false);
                if (AfterSaveDo != null) _workbook.AfterSave += new Interop.Excel.WorkbookEvents_AfterSaveEventHandler(AfterSaveDo);
            }

            _app.Visible = true;
            _app.WindowState = Interop.Excel.XlWindowState.xlNormal;
            _disposeTimer = new System.Timers.Timer(1000);
            _disposeTimer.Elapsed += new System.Timers.ElapsedEventHandler(disposeLoop);
            _disposeTimer.Start();
        }

        /// <summary>
        /// Why need Dispose Loop ?
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void disposeLoop(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (_app == null) return;
            if (_app.Visible) return;
            this.Dispose();
        }


        public void SetWorkArea(System.Drawing.Rectangle workarea)
        {
            // 2 Ways to use MoveWindow or myExcel.Top/Left & Width/Height
            MoveWindow((System.IntPtr)_app.Hwnd, workarea.X, workarea.Y, workarea.Width, workarea.Height, true);
        }

        #region IDisposable Members
        public void Dispose() // Explicit (user call outside) call to this method (khac voi implicit call - Gabage Collector tu dong goi)
        {
            Dispose(true); // Goi ham Dispose chinh
            GC.SuppressFinalize(this); // Tranh goi Finalizer (dich noi tu Destructor <- Call Implicit form Gabarge Collector)
        }

        protected virtual void Dispose(bool disposing) // Ham dispose chinh
        {
            if (_app == null) return; // Khi ma dong cua so thi dieu gi se xay ra ? // _app co bang null khong ?
            // Else _app ton tai -> Close App and wait for finalization
            if (disposing) // Neu dispose(true) tuc la Explicit call
            {
                // Free other state (manage objects).
            }
            // Free your own state (unmanage objects).

            // Set large field to null.
            _app = null;
            _workbook = null;
            _filename = null;
            _disposeTimer = null;

            GC.Collect(); // GC will collect this : call Destructor 1 lan nua ??? Tao loop vo tan a
            GC.WaitForPendingFinalizers(); // Wait here for long ? Need Test
        }
        #endregion

        ~wExcel()   // With C++ Destructor will always be called. But in C# 'Cause Destructor can be called right quick, can be 1 hour later or even never be called.
        {           // please use IDisposal Pattern above instead Finalize or Destructor
            // Simply call Dispose(false).
            Dispose(false);
        }
    }

    class wOutlook : IDisposable // Outlook MailItem no need Dispose Manually Isn't it ?
    {
        private Interop.Outlook.Application _app = null;
        private Interop.Outlook.MailItem _mail = null;
        private string _attach = null;
        private System.Timers.Timer _timerdispose = null;
        private Interop.Outlook.Attachment _attachment = null;

        public wOutlook(string title, string to, string cc, System.Windows.Documents.FlowDocument body, System.Windows.Documents.FlowDocument signature, string attachment = "")
        {
            _app = new Interop.Outlook.Application();
            _attach = attachment;
            _mail = (Interop.Outlook.MailItem)_app.CreateItem(Interop.Outlook.OlItemType.olMailItem);
            if (attachment != "") _attachment = _mail.Attachments.Add(_attach, Interop.Outlook.OlAttachmentType.olByValue, 1, Type.Missing);
            _mail.Subject = title;
            _mail.To = to;
            _mail.CC = cc;
            _mail.BodyFormat = Interop.Outlook.OlBodyFormat.olFormatHTML;
            //_mail.HTMLBody = body + NRtfTree.Demo.Rtf2Html.ConvertCode(signature);
            _mail.Importance = Interop.Outlook.OlImportance.olImportanceLow;

            _mail.Display(false);

            _mail.GetInspector.WindowState = Interop.Outlook.OlWindowState.olNormalWindow;

            System.Windows.Controls.RichTextBox rtb1 = new System.Windows.Controls.RichTextBox(signature);
            rtb1.SelectAll(); rtb1.Copy();
            //_mail.GetInspector.Activate();
            //System.Windows.Clipboard.
            

            // FUTURE CODE
            _timerdispose = new System.Timers.Timer(1000);
            _timerdispose.Elapsed += new System.Timers.ElapsedEventHandler(DisposeLoop);
            _timerdispose.Start();
            m_Events = (Interop.Outlook.ItemEvents_Event)_mail;
            m_Events.Close += new Interop.Outlook.ItemEvents_CloseEventHandler(CloseEvent);
        }

        public string HTMLBody
        {
            get { return _mail.HTMLBody; }
            set { _mail.HTMLBody = value; }
        }

        public string RTFBody
        {
            get { return _mail.RTFBody as string; }
            set { _mail.RTFBody = value; }
        }

        public void ReAttach()
        {   
            /*for (int i = 1; i++; i <=_mail.Attachments.Count)
            {
                _mail.Attachments.Remove(i);
            }*/

            /*Co tu dong thay doi gia tri voi link hay phai update lai ?*/
            _attachment.Delete();
            _attachment = _mail.Attachments.Add(_attach, Interop.Outlook.OlAttachmentType.olByValue, 1, Type.Missing);
        }

        private Interop.Outlook.ItemEvents_Event m_Events;

        public void SetWorkArea(System.Drawing.Rectangle workarea)
        {
            _mail.GetInspector.Top = workarea.Y;
            _mail.GetInspector.Left = workarea.X;
            _mail.GetInspector.Width = workarea.Width;
            _mail.GetInspector.Height = workarea.Height;
        }

        private void CloseEvent(ref bool cancel)
        {
            // Code dispose HERE ?
            //this.Dispose();
        }

        private void DisposeLoop(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (_mail == null) return;
        }
        #region IDisposable Members
        public void Dispose() // Explicit (user call outside) call to this method (khac voi implicit call - Gabage Collector tu dong goi)
        {
            // CODE TO MAKE SURE MAIL_ITEM HAD BEEN CLOSED

            Dispose(true); // Goi ham Dispose chinh
            GC.SuppressFinalize(this); // Tranh goi Finalizer (dich noi tu Destructor <- Call Implicit form Gabarge Collector)
        }

        protected virtual void Dispose(bool disposing) // Ham dispose chinh
        {
            if (_app == null) return; // Khi ma dong cua so thi dieu gi se xay ra ? // _app co bang null khong ?
            // Else _app ton tai -> Close App and wait for finalization
            if (disposing) // Neu dispose(true) tuc la Explicit call
            {
                //_app.Quit(); // If dispose explicit call then quit app // Lieu co bao loi cho Outlook. Can Test
                // Free other state (manage objects).
            }
            // Free your own state (unmanage objects).

            // Set large field to null.
            _app = null;
            _mail = null;
            _attach = null;
            _timerdispose = null;
            GC.Collect(); // GC will collect this : call Destructor 1 lan nua ??? Tao loop vo tan a
            GC.WaitForPendingFinalizers(); // Wait here for long ? Need Test
        }
        #endregion

        ~wOutlook()   // With C++ Destructor will always be called. But in C# 'Cause Destructor can be called right quick, can be 1 hour later or even never be called.
        {           // please use IDisposal Pattern above instead Finalize or Destructor
            // Simply call Dispose(false).
            Dispose(false);
        }
    }
}
